﻿using SymulatorEthernetWPF.Shared;
using SymulatorEthernetWPF.SimObjects.Devices;
using SymulatorEthernetWPF.SimObjects.Layers.DataLink;
using SymulatorEthernetWPF.SimObjects.Layers.Physical;
using SymulatorEthernetWPF.SimObjects.Wires;
using SymulatorEthernetWPF.UserInterface;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace SymulatorEthernetWPF.SimObjects
{
    public static class Simulation
    {

        public static ObservableStack<HistoryElement> UndoStack = new ObservableStack<HistoryElement>();
        public static ObservableStack<HistoryElement> RedoStack = new ObservableStack<HistoryElement>();        

        public static int HostCounter = 1;
        public static int SwitchCounter = 1;
        public static int HubCounter = 1;

        private static bool paused = false;
        public static int tickCount = 0;

        public static UIElementCollection simObjects=StaticVars.MainWindow.customCanvas.Children;

        public static ObservableCollection<TaskQueueItem> taskQueue = new ObservableCollection<TaskQueueItem>();
                
        private static DispatcherTimer timer = new DispatcherTimer();

        public static bool isRunning = false;
        private static HistoryElement preSimState = null;

        static Simulation()
        {
            UndoStack.CollectionChanged += UndoStack_CollectionChanged;
            RedoStack.CollectionChanged += RedoStack_CollectionChanged;
        }

        static void RedoStack_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (RedoStack.Count == 0)
            {
                StaticVars.MainWindow.redoButton.IsEnabled = false;
                StaticVars.MainWindow.mainMenu_Redo.IsEnabled = false;
                StaticVars.MainWindow.mainMenu_redoIcon.Source = StaticVars.RedoInactive;
                StaticVars.MainWindow.toolbar_redoIcon.Source = StaticVars.RedoInactive;
            }
            else
            {
                StaticVars.MainWindow.redoButton.IsEnabled = true;
                StaticVars.MainWindow.mainMenu_Redo.IsEnabled = true;
                StaticVars.MainWindow.mainMenu_redoIcon.Source = StaticVars.RedoActive;
                StaticVars.MainWindow.toolbar_redoIcon.Source = StaticVars.RedoActive;
            }
        }

        static void UndoStack_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (UndoStack.Count == 0)
            {
                StaticVars.MainWindow.undoButton.IsEnabled = false;
                StaticVars.MainWindow.mainMenu_Undo.IsEnabled = false;
                StaticVars.MainWindow.mainMenu_undoIcon.Source = StaticVars.UndoInactive;
                StaticVars.MainWindow.toolbar_undoIcon.Source = StaticVars.UndoInactive;
            }
            else
            {
                StaticVars.MainWindow.undoButton.IsEnabled = true;
                StaticVars.MainWindow.mainMenu_Undo.IsEnabled = true;
                StaticVars.MainWindow.mainMenu_undoIcon.Source = StaticVars.UndoActive;
                StaticVars.MainWindow.toolbar_undoIcon.Source = StaticVars.UndoActive;
            }
        }

        static public void reset()
        {
            simObjects.RemoveRange(0, simObjects.Count);
            taskQueue.Clear();
            RedoStack.Clear();
            UndoStack.Clear();
            HostCounter = 1;
            SwitchCounter = 1;
            HubCounter = 1;
            isRunning = false;
        }

        static public void startSim()
        {
            StaticVars.MainWindow.pauseSimButton.IsEnabled = true;
            StaticVars.MainWindow.stopSimButton.IsEnabled = true;
            StaticVars.MainWindow.startSimButton.IsEnabled = false;
            isRunning = true;
            if (!paused)
            {
                preSimState = new HistoryElement();
                timer.Stop();
                timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromSeconds(1);
                timer.Tick += timer_Tick;
                timer.Start();

            }
            else
            {
                for (int i = 0; i < simObjects.Count; i++)
                {
                    if (simObjects[i].GetType() == typeof(Signal))
                    {
                        ((Signal)simObjects[i]).resume();
                    }
                }
                paused = false;
            }
        }

        static void timer_Tick(object sender, EventArgs e)
        {
            StaticVars.MainWindow.statusLabel.ShowMessage(tickCount.ToString());
            tickCount++;
            foreach (TaskQueueItem it in taskQueue)
            {
                if ((it.time == tickCount || (tickCount>it.time && (tickCount-it.time)%it.repeat==1)) && it.active)
                {
                    foreach (UIElement itUI in simObjects)
                    {
                        if (itUI is DeviceControl)
                        {
                            if (((DeviceControl)itUI).GUID == it.sourceDeviceGUID)
                            {
                                ((DeviceControl)itUI).sendFrame(new Ethernet(it.destination, it.source));
                                break;
                            }
                        }
                    }
                }
            }
        }

        static public void stopSim()
        {

            tickCount = 0;
            timer.Stop();
            paused = false;
            isRunning = false;
            StaticVars.MainWindow.pauseSimButton.IsEnabled = false;
            StaticVars.MainWindow.stopSimButton.IsEnabled = false;
            StaticVars.MainWindow.startSimButton.IsEnabled = true;
            for (int i = simObjects.Count-1; i >=0; i--)
            {                
                try
                {
                        if (simObjects[i] is Signal)
                        {
                            ((Signal)simObjects[i]).stop();
                        }
                        if (simObjects[i] is DeviceControl)
                        {
                            ((DeviceControl)simObjects[i]).reset();
                            foreach (NetworkInterface it in ((DeviceControl)simObjects[i]).interfaces)
                            {
                                it.reset();
                            }
                        }
                }
                catch { }
            }
            Simulation.simObjects.Clear();
            
            foreach (ISerializable it in preSimState.Controls)
            {
                if (it is UIElement)
                {
                    StaticVars.MainWindow.customCanvas.Children.Add((UIElement)it);
                    if (it is Wire)
                        ((Wire)it).updateWire();
                }
            }
            Simulation.taskQueue.Clear();
            foreach (TaskQueueItem it in preSimState.TaskQueueItems)
            {
                Simulation.taskQueue.Add(it);
            }
            preSimState = null;
            

        }

        static public void pauseSim()
        {
            StaticVars.MainWindow.pauseSimButton.IsEnabled = false;
            StaticVars.MainWindow.stopSimButton.IsEnabled = true;
            StaticVars.MainWindow.startSimButton.IsEnabled = true;
            for (int i = 0; i < simObjects.Count; i++)
            {
                if (simObjects[i].GetType() == typeof(Signal))
                {
                    ((Signal)simObjects[i]).pause();
                }
            }
            paused = true;

        }
    }
}
